//pbh mcp networks server
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>


#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#define BUFSIZE 4096
void error(char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
   //variables in common
   int sock, len, fromlen, n;
   struct sockaddr_in server;
   struct sockaddr_in from;
   struct timeval start_time;
   
   //process init
   pid_t pid;
   pid = fork();
   
   if ( pid == 0) // is child
   {
//-------------------------------TCP HERE------------------------------------
      //timing stuff
      struct timeval cur_time;

      int newsock;
      unsigned short port;
      char buffer[BUFSIZE];
      char band_send[1400];
      char *rtt = "r";

      if (argc < 2) 
      {
         fprintf(stderr,"usage %s portnumber\n",argv[0]);
         exit(0);
      }
      
      fromlen = sizeof(from);
      port = (unsigned short) atoi(argv[1]);
      
      //networking commences
      sock = socket(AF_INET, SOCK_STREAM, 0);
      if (sock < 0) 
         error("Opening socket");
         
      server.sin_family=AF_INET;
      server.sin_addr.s_addr=INADDR_ANY;
      server.sin_port=htons(port);  

      //tcp setup
      if (bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) 
          error("binding socket");
      
      if (listen(sock,5) < 0) 
          error("listening");
      
      while (1) 
      {
         //printf("Waiting for connection\n");
         newsock = accept( sock, (struct sockaddr *) &from, &fromlen);
         if (newsock < 0) error("Accepting");
         //printf("A TCP connection has been accepted from %s\n",         inet_ntoa((struct in_addr)from.sin_addr));
         
         n = recv(newsock,buffer,20,0);

         if ( atoi(buffer) != 0 ) //now doing a TCP bandwidth test, sending tons of data
         {
            printf("In TCP Bandwidth Test...");
            
            gettimeofday(&start_time, NULL); //start timer
            do 
            {
               n = send(newsock, band_send, 1400, 0); //MSG_NOSIGNAL
               gettimeofday(&cur_time, NULL); //poll time
            } while ( ( ( cur_time.tv_sec*1000000 + cur_time.tv_usec) - 
                        ( start_time.tv_sec *1000000  + start_time.tv_usec )  ) 
                         < (atoi(buffer)*1000000 + 100) ); 
                         // run for *buffer* second plus 100 usec
           printf(" TCP Bandwidth Done.\n");
         } else if (buffer[0] == 'r') {
            //RTT test
            //printf(" TCP RTT Test\n");
            n = send(newsock, rtt, strlen(rtt), 0); //MSG_NOSIGNAL
         }
         
         //Read %d bytes from client\n", n);
         if (n < 1)  
            error("Reading");  
         else 
         {
            buffer[n]='\0';
            //printf(" Message from client is: %s\n",buffer);
            //n = send(newsock,msg,strlen(msg),0);
            //if (n < strlen(msg)) 
            // error("Error writing");
            if (close(newsock) < 0) 
               error("closing");           
         }
      } //endwhile
      return 0; // we never get here 
   }
   else if (pid > 0) //is parent
   {
//--------------------------UDP BELOW-----------------------------------------
      char buf[1024];
      struct timeval current_time;
      time_t time_result;

      char fourteen[1400];
      int i;
      int count;

      if (argc < 2) {
         fprintf(stderr, "ERROR, no port provided\n");
         exit(0);
      }
      
      sock=socket(AF_INET, SOCK_DGRAM, 0); //SOCKET
      if (sock < 0) 
         error("Opening socket");
      
      len = sizeof(server);
      bzero(&server,len);
      server.sin_family=AF_INET;
      server.sin_addr.s_addr=INADDR_ANY;
      server.sin_port=htons(atoi(argv[1])+1);
      if (bind(sock,(struct sockaddr *)&server,len)<0)  //BIND
          error("binding");
      fromlen = sizeof(struct sockaddr_in);

      while (1) {
          n = recvfrom(sock,buf,1024,0,(struct sockaddr *)&from,&fromlen); //RECVFROM
          if (n < 0) error("recvfrom");
         //printf("while...\n");
         //printf("buf = %s\n", buf);
         //printf("atoi(buf)= %d\n", atoi(buf));

         if ((atoi(buf) != 0) && (buf[0] != 'r'))
         {
            printf("UDP Bandwidth Test\n");
            count = atoi(buf);
            count += 4;
            printf(" Sending for %d seconds...\n", count);
            gettimeofday(&start_time, NULL);
            do
            {
               n = sendto(sock,fourteen,1400,0,(struct sockaddr *)&from,fromlen);
               if (n  < 0) error("sendto");
               gettimeofday(&current_time, NULL);
               //printf("do...\n");
               //printf("time = %d\n", ((1000000 * current_time.tv_sec + current_time.tv_usec) - (1000000 * start_time.tv_sec + start_time.tv_usec)));

            } while(((1000000 * current_time.tv_sec + current_time.tv_usec) - (1000000 * start_time.tv_sec + start_time.tv_usec))< (count*1000000));
            //printf("leave do\n");
            printf("UDP Bandwidth Done\n");
         }//close bandwidth response

         if (buf[0] == 'r'){ //If its an RTT Test
            //n = recvfrom(sock,buf,1024,0,(struct sockaddr *)&from,&fromlen); //RECVFROM
            //if (n < 0) error("recvfrom");
            //write(1,"Received a datagram: ",21);
            //write(1,buf,n);
            //printf("UDP RTT Test\n");
            n = sendto(sock,"r",1, 0,(struct sockaddr *)&from,fromlen);
            if (n  < 0) error("sendto");
         }//end RTT test
      }//close infinite loop
   }

}
